/***************************************************************************//**
 * @file
 * @brief app_tick.c
 *******************************************************************************
 * # License
 * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
 *******************************************************************************
 *
 * SPDX-License-Identifier: Zlib
 *
 * The licensor of this software is Silicon Laboratories Inc.
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 *
 ******************************************************************************/

// -----------------------------------------------------------------------------
//                                   Includes
// -----------------------------------------------------------------------------
#include <stdint.h>
#include "sl_component_catalog.h"
#include "sl_flex_assert.h"
#include "rail.h"
#include "rf_process.h"
#include "rail_config.h"
#include "sl_rail_util_init.h"
#include "app_task.h"
#include "common.h"
// -----------------------------------------------------------------------------
//                              Macros and Typedefs
// -----------------------------------------------------------------------------
/// Size of RAIL RX/TX FIFO
#define RAIL_FIFO_SIZE (256u)
/// Transmit data length
#define TX_PAYLOAD_LENGTH (16u)

/// State machine of simple_trx
typedef enum {
  S_PACKET_RECEIVED,
  S_PACKET_SENT,
  S_RX_PACKET_ERROR,
  S_TX_PACKET_ERROR,
  S_CALIBRATION_ERROR,
  S_IDLE,
} state_t;

// -----------------------------------------------------------------------------
//                          Static Function Declarations
// -----------------------------------------------------------------------------
/**************************************************************************//**
 * The function printfs the received rx message.
 *
 * @param rx_buffer Msg buffer
 * @param length How many bytes should be printed out
 * @returns None
 *****************************************************************************/
//static void printf_rx_packet(const uint8_t * const rx_buffer, uint16_t length);

/******************************************************************************
 * The API helps to unpack the received packet, point to the payload and returns the length.
 *
 * @param rx_destination Where should the full packet be unpacked
 * @param packet_information Where should all the information of the packet stored
 * @param start_of_payload Pointer where the payload starts
 * @return The length of the received payload
 *****************************************************************************/
static uint16_t unpack_packet(uint8_t *rx_destination, const RAIL_RxPacketInfo_t *packet_information, uint8_t **start_of_payload);

/******************************************************************************
 * The API prepares the packet for sending and load it in the RAIL TX FIFO
 *
 * @param rail_handle Which rail handlers should be used for the TX FIFO writing
 * @param out_data The payload buffer
 * @param length The length of the payload
 *****************************************************************************/
static void prepaire_package(RAIL_Handle_t rail_handle, uint8_t *out_data, uint16_t length);

// -----------------------------------------------------------------------------
//                                Global Variables
// -----------------------------------------------------------------------------
/// Flag, indicating transmit request (button has pressed / CLI transmit request has occured)
volatile bool tx_requested = false;
/// Flag, indicating received packet is forwarded on CLI or not
volatile bool rx_requested = true;

// -----------------------------------------------------------------------------
//                                Static Variables
// -----------------------------------------------------------------------------
/// The variable shows the actual state of the state machine
static volatile state_t state = S_IDLE;

/// Contains the last RAIL Rx/Tx error events
static volatile uint64_t error_code = 0;

/// Contains the status of RAIL Calibration
static volatile RAIL_Status_t calibration_status = 0;

/// RAIL Rx packet handle
static volatile RAIL_RxPacketHandle_t rx_packet_handle;

static RAIL_RxPacketDetails_t packetDetails;

static union {
  // Used to align this buffer as needed
  RAIL_FIFO_ALIGNMENT_TYPE align[RAIL_FIFO_SIZE / RAIL_FIFO_ALIGNMENT];
  uint8_t fifo[RAIL_FIFO_SIZE];
} tx_fifo;

/// Flags to update state machine from interrupt
static volatile bool packet_recieved = false;
static volatile bool packet_sent = false;
static volatile bool rx_error = false;
static volatile bool tx_error = false;
static volatile bool cal_error = false;




volatile uint32_t usTime = 0;
RAIL_RxPacketInfo_t packet_info;

//Status indicator of the RAIL API calls
RAIL_Status_t rail_status = RAIL_STATUS_NO_ERROR;
#define MinimumLengthLimit 6        /*最小长度限制*/
// -----------------------------------------------------------------------------
//                          Public Function Definitions
// -----------------------------------------------------------------------------
/******************************************************************************
 * Application state machine, called infinitely
 *****************************************************************************/
struct receiver_buffer_s receiver_buffer[5] = {0};
static uint32_t loss_packet_no_empty = 0;
static uint32_t loss_packet_too_long = 0;
int rfPackageParse(RAIL_Handle_t rail_handle)
{

    (void)rail_handle;
    struct receiver_buffer_s *receiver = NULL;
    for(uint32_t i = 0; i < (sizeof(receiver_buffer) / sizeof(receiver_buffer[0])); i++)
    {
        if(!receiver_buffer[i].used)
        {
            receiver = &receiver_buffer[i];
        }
    }

    if((rx_packet_handle != RAIL_RX_PACKET_HANDLE_INVALID) && receiver) {
        uint8_t *start_of_packet = 0;
        uint16_t packet_size = unpack_packet(receiver->buff, &packet_info, &start_of_packet);
        receiver->lens = packet_size;
        RAIL_GetRxPacketDetails(rail_handle, rx_packet_handle, &packetDetails);  //获取数据包详细数据
        receiver->rssi = packetDetails.rssi;
        receiver->used = true;
        radio_operation_t operation = {0};
        operation.type = RADIO_RECEIVER;
        operation.radio_rx.buff = receiver;
        rf_msg_receiver_success_notify(operation);
        return 0;
    }
    else if(!receiver)
    {
        loss_packet_no_empty++;
    }
    return -1;
}

void sl_rail_util_on_assert_failed(RAIL_Handle_t rail_handle,
                                   RAIL_AssertErrorCodes_t error_code)
{
  (void) rail_handle;
  (void) error_code;

  NVIC_SystemReset();
  while(1);
}

extern void rf_msg_send_success_notify(void);
/******************************************************************************
 * RAIL callback, called if a RAIL event occurs.
 *****************************************************************************/
void sl_rail_util_on_event(RAIL_Handle_t rail_handle, RAIL_Events_t events)
{
  // Handle Rx events
  if ( events & RAIL_EVENTS_RX_COMPLETION ) {
    if (events & RAIL_EVENT_RX_PACKET_RECEIVED) {
      // Keep the packet in the radio buffer, download it later at the state machine
        RAIL_HoldRxPacket(rail_handle);
        rx_packet_handle = RAIL_GetRxPacketInfo(rail_handle, RAIL_RX_PACKET_HANDLE_OLDEST_COMPLETE, &packet_info);
        if(SYSTEM_IS_RUNNING() && (packet_info.packetBytes <= 64)) //系统启动后调用一下函数
        {
            rfPackageParse(rail_handle);
        }
        else if(packet_info.packetBytes > 64)
        {
            loss_packet_too_long++;
        }
        RAIL_ReleaseRxPacket(rail_handle, rx_packet_handle);      //释放接收包
        packet_recieved = true;
    } else {
      // Handle Rx error
//      RAIL_Idle(rail_handle, RAIL_IDLE, true);
//      RAIL_ResetFifo(rail_handle, true, true);
//      RAIL_StartRx(rail_handle, CHANNEL, NULL);
      rx_error = true;
    }
  }
  // Handle Tx events
  if ( events & RAIL_EVENTS_TX_COMPLETION) {
    if (events & RAIL_EVENT_TX_PACKET_SENT) {
      packet_sent = true;
      if(SYSTEM_IS_RUNNING()) //系统启动后调用一下函数
      {
          rf_msg_send_success_notify();
      }
    } else {
      // Handle Tx error
      tx_error = true;
    }
  }
  // Perform all calibrations when needed
  if ( events & RAIL_EVENT_CAL_NEEDED ) {
    calibration_status = RAIL_Calibrate(rail_handle, NULL, RAIL_CAL_ALL_PENDING);
    if (calibration_status != RAIL_STATUS_NO_ERROR) {
      cal_error = true;
    }
  }
}

/******************************************************************************
 * Button callback, called if any button is pressed or released.
 *****************************************************************************/
//void sl_button_on_change(const sl_button_t *handle)
//{
//  if (sl_button_get_state(handle) == SL_SIMPLE_BUTTON_PRESSED) {
//    tx_requested = true;
//  }
//}

/******************************************************************************
 * Set up the rail TX fifo for later usage
 * @param rail_handle Which rail handler should be updated
 *****************************************************************************/
void set_up_tx_fifo(RAIL_Handle_t rail_handle)
{
  //uint16_t allocated_tx_fifo_size = 0;
  //allocated_tx_fifo_size = RAIL_SetTxFifo(rail_handle, tx_fifo.fifo, 0, RAIL_FIFO_SIZE);
  RAIL_SetTxFifo(rail_handle, tx_fifo.fifo, 0, RAIL_FIFO_SIZE);
//  APP_ASSERT(allocated_tx_fifo_size == RAIL_FIFO_SIZE,
//             "RAIL_SetTxFifo() failed to allocate a large enough fifo (%d bytes instead of %d bytes)\n",
//             allocated_tx_fifo_size,
//             RAIL_FIFO_SIZE);
}

// -----------------------------------------------------------------------------
//                          Static Function Definitions
// -----------------------------------------------------------------------------
/******************************************************************************
 * The API forwards the received rx packet on CLI
 *****************************************************************************/
//static void printf_rx_packet(const uint8_t * const rx_buffer, uint16_t length)
//uint8_t WriteBuffer[100];
void printf_rx_packet(const uint8_t * const rx_buffer, uint16_t length)
{
  //memcpy(WriteBuffer, rx_buffer, length % 100);
  (void) rx_buffer;
  (void) length;
//  DEBUGL((const char *)rx_buffer, length % 100 , true);
}


/******************************************************************************
 * The API helps to unpack the received packet, point to the payload and returns the length.
 *****************************************************************************/
static uint16_t unpack_packet(uint8_t *rx_destination, const RAIL_RxPacketInfo_t *packet_information, uint8_t **start_of_payload)
{
  RAIL_CopyRxPacket(rx_destination, packet_information);
  *start_of_payload = rx_destination;
  return ((packet_information->packetBytes > RAIL_FIFO_SIZE) ? RAIL_FIFO_SIZE : packet_information->packetBytes);
}

/******************************************************************************
 * The API prepares the packet for sending and load it in the RAIL TX FIFO
 *****************************************************************************/
static void prepaire_package(RAIL_Handle_t rail_handle, uint8_t *out_data, uint16_t length)
{
  // Check if write fifo has written all bytes
  //uint16_t bytes_writen_in_fifo = 0;
  //bytes_writen_in_fifo = RAIL_WriteTxFifo(rail_handle, out_data, length, true);
  RAIL_WriteTxFifo(rail_handle, out_data, length, true);
}


/******************************************************************************
 * The function is used for some basic initialization related to the app.
 *****************************************************************************/
RAIL_Handle_t rail_init(void)
{

  // Get RAIL handle, used later by the application
  RAIL_Handle_t rail_handle = sl_rail_util_get_handle(SL_RAIL_UTIL_HANDLE_INST0);

  set_up_tx_fifo(rail_handle);

  // Start reception
  RAIL_Status_t status = RAIL_StartRx(rail_handle, CHANNEL, NULL);
 // APP_WARNING(status == RAIL_STATUS_NO_ERROR, "After initialization RAIL_StartRx() result:%d ", status);

   while(status != RAIL_STATUS_NO_ERROR);

  return rail_handle;
}

volatile RAIL_Status_t RAIL_Status;

uint8_t rail_send(RAIL_Handle_t rail_handle, uint8_t *out_data, uint16_t length)
{
    prepaire_package(rail_handle, out_data, length);
//    return RAIL_StartTx(rail_handle, CHANNEL, RAIL_TX_OPTIONS_DEFAULT, NULL);
    RAIL_Status = RAIL_StartTx(rail_handle, CHANNEL, RAIL_TX_OPTIONS_DEFAULT, NULL);

    return RAIL_Status;
}

uint8_t EFR32_SendPacket(RAIL_Handle_t rail_handle, uint8_t *out_data, uint8_t length, void (*wait)(void))
{
  RAIL_Status_t rail_status = RAIL_STATUS_NO_ERROR;
//  RAIL_Idle(rail_handle,RAIL_IDLE,true);
//  RAIL_ResetFifo(rail_handle,true,true);
  rail_send(rail_handle, out_data, length);
  wait();
  RAIL_Idle(rail_handle,RAIL_IDLE,true);
  RAIL_ResetFifo(rail_handle,true,true);
  RAIL_StartRx(rail_handle, CHANNEL, NULL);//确定接收后的状态,接收数据后变成IDLE态，因此要手动进入接收##
  return true;
}

